package com.gitee.sop.gateway.open;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gitee.sop.gateway.open.base.*;
import com.gitee.sop.gatewaycommon.bean.Isv;
import com.gitee.sop.gatewaycommon.bean.SopConstants;
import com.gitee.sop.gatewaycommon.gateway.ServerWebExchangeUtil;
import com.gitee.sop.gatewaycommon.secret.IsvManager;
import com.gitee.sop.gatewaycommon.util.RequestUtil;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 开放功能接口
 *
 * @author: Admin
 * @date: 2021/3/16
 * @description:
 * @copyright: 重庆万蓝兴科技有限公司
 */
//@Api(tags = "开放功能接口（蓝星云开放平台）")
@RestController
public class OpenApiController {

    private final static String indexPath = "http://localhost:8081";

    @Resource
    private IsvManager isvManager;


    @Autowired
    private ServerCodecConfigurer codecConfigurer;

    @PostMapping(value = "/lxyCloud/forward/{appId}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public Mono<Object> forward(@PathVariable String appId, ServerWebExchange exchange) {
        ServerRequest serverRequest = ServerWebExchangeUtil.createReadBodyRequest(exchange, codecConfigurer);
        // 读取请求体中的内容
        Mono<Object> mono = serverRequest.bodyToMono(byte[].class)
                .switchIfEmpty(Mono.just("".getBytes()))
                .flatMap(data -> {
                    Map<String, Object> bizMap = new HashMap<>();
                    List<MultipartFile> multipartFiles = new ArrayList<>();
                    MediaType contentType = exchange.getRequest().getHeaders().getContentType();
                    if (Objects.isNull(contentType)) {
                        contentType = MediaType.APPLICATION_FORM_URLENCODED;
                    }
                    String contentTypeStr = contentType.toString().toLowerCase();
                    if (StringUtils.containsAny(contentTypeStr, "json", "text")) {
                        JSONObject jsonObject = JSON.parseObject(new String(data, SopConstants.CHARSET_UTF8));
                        bizMap.putAll(jsonObject);
                    } else if (StringUtils.containsIgnoreCase(contentTypeStr, "multipart")) {
                        // 文件参数
                        HttpServletRequest fileUploadRequest = ServerWebExchangeUtil.getFileUploadRequest(exchange, data);
                        multipartFiles.addAll(getUploadInfo(fileUploadRequest, bizMap));
                    } else {
                        // APPLICATION_FORM_URLENCODED请求
                        Map<String, String> map = RequestUtil.parseQueryToMap(new String(data, SopConstants.CHARSET_UTF8));
                        bizMap.putAll(map);
                    }
                    String params = bizMap.get("params").toString();
                    bizMap.remove("params");
                    if (StringUtils.isNotBlank(params)) {
                        JSONObject jsonObject = JSONObject.parseObject(params);
                        bizMap.putAll(jsonObject);
                    }
                    ServerHttpRequest request = exchange.getRequest();
                    RequestMethod requestMethod = RequestMethod.GET;
                    Object o = commonSend(appId, requestMethod, bizMap, multipartFiles, request);
                    return Mono.just(o);
                });
        return mono;
    }


    /**
     * 获取上传文件内容
     *
     * @param request request
     * @return 返回文件内容和表单内容
     */
    public List<MultipartFile> getUploadInfo(HttpServletRequest request, Map<String, Object> bizMap) {
        if (request instanceof StandardMultipartHttpServletRequest) {
            return getUploadInfo((StandardMultipartHttpServletRequest) request, bizMap);
        }
        // 创建一个文件上传解析器
        ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
        List<MultipartFile> multipartFileList = new ArrayList<>(16);
        try {
            List<FileItem> fileItems = upload.parseRequest(request);
            for (FileItem fileItem : fileItems) {
                if (fileItem.isFormField()) {
                    bizMap.put(fileItem.getFieldName(), fileItem.getString("utf-8"));
                } else {
                    multipartFileList.add(new CommonsMultipartFile(fileItem));
                }
            }
        } catch (Exception e) {

        }
        return multipartFileList;
    }

    private final static Map<String, OpenClient> openClientMap = new ConcurrentHashMap<String, OpenClient>();

    /**
     * 通用发送处理
     *
     * @param requestMethod  请求方式
     * @param bizMap         业务参数
     * @param servletRequest 请求
     * @return
     */
    private Object commonSend(String appId, RequestMethod requestMethod, Map<String, Object> bizMap, List<MultipartFile> multipartFiles, ServerHttpRequest servletRequest) {
        Object m = bizMap.get("method");
        if (Objects.isNull(m) || StringUtils.isBlank(m.toString())) {
            throw new RuntimeException("方法名不能为空");
        }
        CommonRequest request = new CommonRequest(m.toString());
        request.setBizModel(bizMap);
        request.setRequestMethod(requestMethod);

        if (Objects.nonNull(multipartFiles) && multipartFiles.size() > 0) {
            List<UploadFile> files = multipartFiles.stream()
                    .map(multipartFile -> {
                        try {
                            return new UploadFile(multipartFile.getName(), multipartFile.getOriginalFilename(), multipartFile.getBytes());
                        } catch (IOException e) {
                            return null;
                        }
                    })
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());
            if (Objects.nonNull(files) && files.size() > 0) {
                request.setFiles(files);
            }
        }
        String appAuthToken = getAppAuthToken(bizMap, servletRequest);
        OpenClient openClient = openClientMap.get(appId);
        if (null == openClient) {
            Isv isv = isvManager.getIsv(appId);
            openClient = new OpenClient(indexPath, isv.getAppKey(), isv.getSecretInfo1());
            openClientMap.put(appId, openClient);
        }
        CommonResponse response = openClient.execute(request, appAuthToken);
        if (response.isSuccess()) {
            // 返回结果，body对应的是alipay_story_find_response部分
            String body = response.getBody();
            JSONObject jsonObject = JSON.parseObject(body);
            return jsonObject;
        }
        String message = StringUtils.isNotBlank(response.getSubMsg()) ? response.getSubMsg() : response.getMsg();
        return R.fail(null, message);
    }

    /**
     * 获取用户请求token
     *
     * @param bizMap         参数集
     * @param servletRequest 请求
     * @return
     */
    private String getAppAuthToken(Map<String, Object> bizMap, ServerHttpRequest servletRequest) {
        String appAuthToken = servletRequest.getHeaders().getFirst("LXY-APP-AUTH-TOKEN");
        if (StringUtils.isBlank(appAuthToken)) {
            appAuthToken = servletRequest.getQueryParams().getFirst("LXY-APP-AUTH-TOKEN");
        }
        if (StringUtils.isBlank(appAuthToken)) {
            Object authToken = bizMap.get("LXY-APP-AUTH-TOKEN");
            if (Objects.nonNull(authToken)) {
                appAuthToken = authToken.toString();
            }
        }

        if (StringUtils.isBlank(appAuthToken)) {
            appAuthToken = null;
        }
        return appAuthToken;
    }

}
